﻿
namespace LFSRecord2.Model.Sound
{
    /// <summary>
    /// Simple but effective peak limiter. Works with 32bit float values. For now just a simple static class.
    /// </summary>
    static class PeakLimiter
    {
        /// <summary>
        /// Limiter threshold. Signals below threshold pass through unaffected.
        /// </summary>
        static float _limitThreshold = 0.85f;

        /// <summary>
        /// The amount of room above threshold.
        /// </summary>
        static float _limitRoom = 1.0f - _limitThreshold;

        /// <summary>
        /// Maximum peak amplitude that we'll limit nicely. Signals beyond this amplitude are simply capped to 1 (or -1).
        /// </summary>
        static float _maxPeak = 1.5f;

        /// <summary>
        /// The amount of room above threshold until max peak is reached.
        /// </summary>
        static float _maxRoom = _maxPeak - _limitThreshold;

        /// <summary>
        /// Multiplyer used in the actual limiting algorythm. It's based on the other variables in this class.
        /// </summary>
        static float _peakLimitMult = _limitRoom / _maxRoom;

        /// <summary>
        /// Limit the given float sample
        /// </summary>
        /// <param name="sample">A single audio sample, provided as a float</param>
        /// <returns>The limited sample</returns>
        public static float Limit(float sample)
        {
            if (sample < 0)
            {
                if (sample > -_limitThreshold)
                    return sample;
                sample = -sample;

                // Bring down the dynamic range of _maxPeak - _limitThreshold to 1 - _limitThreshold
                sample = _limitThreshold + (sample - _limitThreshold) * _peakLimitMult;
                if (sample > 1)
                    return -1.0f;
                return -sample;
            }
            else
            {
                if (sample < _limitThreshold)
                    return sample;

                // Bring down the dynamic range of _maxPeak - _limitThreshold to 1 - _limitThreshold
                sample = _limitThreshold + (sample - _limitThreshold) * _peakLimitMult;
                if (sample > 1)
                    return 1.0f;
                return sample;
            }
        }
    }
}
